
<template>
  <div style="position: relative">
    <Form
      ref="form"
      :model="param"
      :rules="rules"
      :label-width="labelPosition === 'top' ? undefined : labelWidth"
      :label-position="labelPosition"
      class="customed-edit-form"
      :class="{ search: operateType === 'search', view: operateType === 'view' }"
      :size="size"
    >
      <Row>
        <i-col
          span="24"
          v-if="submitShow && !submitHide && submitPosition === 'top'"
          class="submit-col"
        >
          <Button
            type="primary"
            :size="size"
            @click.prevent="submit"
            :disabled="submitDisabled"
          >{{submitText}}</Button>
        </i-col>

        <template v-for="(info,i) in infos">
          <i-col
            class="form-col"
            :key="i"
            :class-name="`col-${info.key}`"
            :span="info.colSpan ? info.colSpan : colSpan ? colSpan : info.type === 'hr' ? '24' : '12'"
            :style="info.style"
          >
            <slot
              name="up"
              :info="info"
            ></slot>
            <components
              :is="`${info.type || 'input'}-item`"
              :info="info"
              :size="info.size || size"
              v-if="linkingHandler(info, param)"
              v-model="param[info.key]"
              :model="param"
              :activeItem="activeItem"
              :operateType="operateType"
              @setActiveItem="v => activeItem = v"
              @on-enter="$emit('on-enter', param)"
              @on-clear="$emit('on-clear', param)"
              @update="v => spinShow = v"
              @focus="v => $emit('focus', v, info)"
              @blur="v => $emit('blur', v, info)"
              :key="`components-${i}`"
              :ref="info.key"
            >
              <slot
                :name="info.key"
                :info="info"
              ></slot>
              <slot :info="info"></slot>
            </components>
            <slot
              name="down"
              :info="info"
            ></slot>
          </i-col>
        </template>

        <i-col
          span="24"
          v-if="submitShow && !submitHide && submitPosition === 'bottom'"
          class="submit-col"
        >
          <Button
            v-if="submitShape"
            type="primary"
            :size="size"
            @click.prevent="submit"
            :long="submitLong"
            shape="circle"
            :disabled="submitDisabled"
          >{{submitText}}</Button>
          <Button
            v-else
            type="primary"
            :size="size"
            @click.prevent="submit"
            :long="submitLong"
            :disabled="submitDisabled"
          >{{submitText}}</Button>
        </i-col>
      </Row>
    </Form>
    <Spin
      fix
      v-if="spinShow"
    ></Spin>
  </div>
</template>

<script>
import components from './register'
import { infos, rules, saveForm } from './mock'
import { getDateAll } from './utils'
import { Row, Col, Button, Form, Spin } from 'view-design'
export default {
  name: 'EditForm',
  getDateAll,
  components: Object.assign(
    {},
    components,
    {
      Row,
      iCol: Col,
      Button,
      Form,
      Spin
    }
  ),
  props: {
    // 显示类型：编辑edit、查看view、表格搜索search
    operateType: {
      type: String,
      default: 'edit'
    },
    infos: {
      type: Array,
      default: () => infos
    },
    rules: {
      type: [Object, Array, Boolean, Function],
      default: () => rules
    },
    labelWidth: {
      type: Number,
      default: 100
    },
    // label位置为top时，label-width属性不存在
    labelPosition: {
      type: String,
      default: 'right'
    },
    // 默认不存在
    colSpan: {
      type: String,
      default: ''
    },
    size: {
      type: String,
      default: 'default'
    },
    // 是否提交无效内容（当value为空字符串时），默认全部提交
    submitVoid: {
      type: Boolean,
      default: true
    },
    // 是否有提交按钮
    submitShow: {
      type: Boolean,
      default: true
    },
    submitHide: {
      type: Boolean,
      default: false
    },
    // 是否有提交按钮
    submitDisabled: {
      type: Boolean,
      default: false
    },
    // 表单做表格搜索栏时的，一般search按钮为top
    submitPosition: {
      type: String,
      default: 'bottom'
    },
    // 提交按钮的文字内容
    submitText: {
      type: String,
      default: '提交'
    },
    // 提交按钮的长度是否为100%
    submitLong: {
      type: Boolean,
      default: false
    },
    // 提交按钮的形状
    submitShape: {
      type: String,
      default: '' // 为真时默认circle
    }
  },
  data () {
    // 初始化param
    const setParam = (infos, param = {}) => {
      infos.map(o => {
        let { key, value, type } = o
        if (type !== 'hr') {
          param[key] = value || (type === 'checkbox' ? [] : '')
        }
        return o
      })
      return param
    }
    return {
      param: setParam(this.infos),
      spinShow: false,
      activeItem: {}
    }
  },
  watch: {
    param: {
      handler (v) {
        this.$emit('on-change', v)
      },
      deep: true
    }
  },
  methods: {
    // mock保存表单的方法
    saveForm,
    // 表单只做展现、校验，提交后的业务逻辑交还给父级
    async submit () {
      let result = await new Promise(resolve => {
        this.$refs.form.validate(valid => resolve(valid))
      })
      if (result) {
        // 处理不显示的表单项参数
        let param = JSON.parse(JSON.stringify(this.param))
        this.infos.map(o => {
          if (!this.linkingHandler(o, this.param)) {
            delete param[o.key]
          }
        })
        // 处理date组件参数（keys里含有逗号的字符串，且对应值是数组的情况）
        let keys = Object.keys(param).filter(k => k.includes(','))
        if (keys.length) {
          keys.map(key => {
            let value = param[key]
            if (Array.isArray(value)) {
              let [start, end] = key.split(',')
              param[start] = value[0]
              param[end] = value[1]
              delete param[key]
            }
          })
        }
        // 处理不提交的数据
        if (!this.submitVoid) {
          Object.keys(param).map(k => {
            if (param[k] === '') {
              delete param[k]
            }
          })
        }
        this.$emit('submit', param)
        this.$emit('ok', param)
        return param
      }
    },
    // 表单重置
    resetFields () {
      this.$refs.form.resetFields()
    },
    // 联动表单项的显隐和是否禁用
    linkingHandler (o, param) {
      if (o.linking) {
        return this.doLinking(o, param)
      }
      return true
    },
    doLinking (o, param) {
      let { key, value, linkingType } = o.linking
      if (linkingType === 'hidden' || linkingType === 'show') {
        let hidden = true
        // 联动：某一项的多个值对本项的显隐控制
        if (Array.isArray(value)) {
          hidden = Array.isArray(param[key])
            ? param[key].some(o => value.includes(o))
            : value.includes(param[key])
          // 联动：某一项的单个值对本项的显隐控制
        } else {
          hidden = Array.isArray(param[key])
            ? param[key].includes(value)
            : param[key] === value
        }
        return linkingType === 'hidden' ? !hidden : hidden
      }
      // 如果是回显状态，则不需要禁用显示
      if (this.operateType !== 'view') {
        /**
         * 这里必须在infos里初始化disabled，否则无效
         * 原因：xxx
         */
        if (linkingType === 'disabled' || linkingType === 'undisabled') {
          // 联动：某一项的多个值对本项的禁用控制
          if (Array.isArray(value)) {
            let disabled = Array.isArray(param[key])
              ? param[key].some(o => value.includes(o))
              : value.includes(param[key])
            if (o.disabled === undefined) {
              throw Error(`infos中${o.key}项配置出错：linkingType为disabled时，item需要设置disabled属性`)
            }
            o.disabled = linkingType === 'disabled' ? disabled : !disabled
            // 联动：某一项的单个值对本项的禁用控制
          } else {
            let disabled = Array.isArray(param[key])
              ? param[key].includes(value)
              : param[key] === value
            if (o.disabled === undefined) {
              throw Error(`infos中${o.key}项配置出错：linkingType为disabled时，item需要设置disabled属性`)
            }
            o.disabled = linkingType === 'disabled' ? disabled : !disabled
          }
        }
      }
      return true
    },
    getVM (key) {
      const ref = this.$refs[key]
      return Array.isArray(ref) ? ref[0] : ref
    }
  }
}
</script>

<style lang="css" scoped>
/* 表单基本样式 */
.customed-edit-form {
  box-sizing: border-box;
  /* padding-right: 10px; */
  text-align: left;
}
.customed-edit-form .form-col {
  box-sizing: border-box;
  /* padding-right: 10px; */
}
.submit-col {
  text-align: right;
}
/* 表单做表格搜索栏时的样式 */
.customed-edit-form.search {
  padding-right: 80px;
}
.customed-edit-form.search .form-col {
  width: auto;
}
.customed-edit-form.search .submit-col {
  text-align: right;
  margin-right: -70px;
  margin-left: auto;
  position: relative;
  z-index: 1;
  height: 0;
  width: auto;
  float: none;
}
</style>
<style lang="css">
/* 表单回显时的样式：
  1、input、textarea、select的边框去掉
  2、阻止date、select等子项的下拉事件，阻止input、textarea等子项的获取焦点事件
  3、隐藏checkbox、radio、upload等子项的icon
*/
.customed-edit-form.view input,
.customed-edit-form.view textarea,
.customed-edit-form.view .ivu-select-selection {
  border-color: transparent;
}
.customed-edit-form.view label,
.customed-edit-form.view .ivu-date-picker,
.customed-edit-form.view .ivu-select,
.customed-edit-form.view input,
.customed-edit-form.view .ivu-input-wrapper,
.customed-edit-form.view textarea {
  pointer-events: none;
  resize: none;
}
.customed-edit-form.view label .ivu-radio-inner,
.customed-edit-form.view label .ivu-checkbox-inner,
.customed-edit-form.view .ivu-input-suffix,
.customed-edit-form.view .ivu-select-arrow,
.customed-edit-form.view .ivu-upload.ivu-upload-drag {
  visibility: hidden;
  pointer-events: none;
}
</style>
